#include "RenderState.h"

#define UpdateBlendState(enable)\
do{\
	enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND);\
} while (0)

#define UpdateDepthTestState(enable)\
do{\
	enable ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);\
} while (0)

#define UpdateAlphaTestState(enable)\
do{\
	enable ? glEnable(GL_ALPHA_TEST) : glDisable(GL_ALPHA_TEST);\
} while (0)

RenderState::RenderState() {
	mbEnableBlend = false;
	mbEnableDepthTest = true;
	mbEnableAlphaTest = false;
	mbWriteR = true;
	mbWriteG = true;
	mbWriteB = true;
	mbWriteA = true;
	mbWriteDepthBuffer = true;
	mSrcBlendFunc = GL_SRC_ALPHA; 
	mDstBlendFunc = GL_ONE_MINUS_SRC_ALPHA;
	mAlphaTestFunction = GL_GREATER;
	mDepthTestFunction = GL_LEQUAL;
	mAlphaTestAlphaValue = 0.1f;
	mDrawFace = GL_FRONT;
	mPolygonModel = GL_FILL;
	mCurrentProgram = 0;
}

RenderState GlobalRenderState::mRenderState;

void GlobalRenderState::Init() {
	UpdateBlendState(mRenderState.mbEnableBlend);
	UpdateDepthTestState(mRenderState.mbEnableDepthTest);
	UpdateAlphaTestState(mRenderState.mbEnableAlphaTest);
	glBlendFunc(mRenderState.mSrcBlendFunc, mRenderState.mDstBlendFunc);
	glColorMask(mRenderState.mbWriteR, mRenderState.mbWriteG, mRenderState.mbWriteB, mRenderState.mbWriteA);
	glDepthMask(mRenderState.mbWriteDepthBuffer);
	glUseProgram(mRenderState.mCurrentProgram);
	glDepthFunc(mRenderState.mDepthTestFunction);
	glPolygonMode(mRenderState.mDrawFace, mRenderState.mPolygonModel);
	glAlphaFunc(mRenderState.mAlphaTestFunction, mRenderState.mAlphaTestAlphaValue);
}

void GlobalRenderState::SetBlendState(bool enable) {
	if (mRenderState.mbEnableBlend != enable) {
		mRenderState.mbEnableBlend = enable;
		UpdateBlendState(enable);
	}
}

void GlobalRenderState::SetBlendFunc(unsigned int src, unsigned int dst) {
	if (mRenderState.mSrcBlendFunc != src || mRenderState.mDstBlendFunc != dst) {
		mRenderState.mSrcBlendFunc = src;
		mRenderState.mDstBlendFunc = dst;
		glBlendFunc(src, dst);
	}
}

void GlobalRenderState::SetDepthTestState(bool enable) {
	if (mRenderState.mbEnableDepthTest != enable) {
		mRenderState.mbEnableDepthTest = enable;
		UpdateDepthTestState(enable);
	}
}

void GlobalRenderState::SetAlphaTestState(bool enable) {
	if (mRenderState.mbEnableAlphaTest != enable) {
		mRenderState.mbEnableAlphaTest = enable;
		UpdateAlphaTestState(enable);
	}
}

void GlobalRenderState::SetColorMask(bool r, bool g, bool b, bool a) {
	if (
		mRenderState.mbWriteR != r ||
		mRenderState.mbWriteG != g ||
		mRenderState.mbWriteB != b ||
		mRenderState.mbWriteA != a) {
		mRenderState.mbWriteR = r;
		mRenderState.mbWriteG = g;
		mRenderState.mbWriteB = b;
		mRenderState.mbWriteA = a;
		glColorMask(r, g, b, a);
	}
}

void GlobalRenderState::SetDepthMask(bool enable) {
	if (mRenderState.mbWriteDepthBuffer != enable) {
		mRenderState.mbWriteDepthBuffer = enable;
		glDepthMask(enable);
	}
}

void GlobalRenderState::SetDepthFunc(unsigned int depthFunc) {
	if (mRenderState.mDepthTestFunction != depthFunc) {
		mRenderState.mDepthTestFunction = depthFunc;
		glDepthFunc(depthFunc);
	}
}

void GlobalRenderState::SetCurrentProgram(unsigned int program) {
	if (mRenderState.mCurrentProgram != program) {
		mRenderState.mCurrentProgram = program;
		glUseProgram(program);
	}
}

void GlobalRenderState::SetPolygonMode(unsigned int face, unsigned int mode) {
	if (mRenderState.mDrawFace != face || mRenderState.mPolygonModel != mode) {
		mRenderState.mDrawFace = face;
		mRenderState.mPolygonModel = mode;
		glPolygonMode(face, mode);
	}
}

void GlobalRenderState::SetAlphaTest(unsigned int func, float ref_value) {
	if (mRenderState.mAlphaTestFunction != func || mRenderState.mAlphaTestAlphaValue != ref_value) {
		mRenderState.mAlphaTestFunction = func;
		mRenderState.mAlphaTestAlphaValue = ref_value;
		glAlphaFunc(func, ref_value);
	}
}
